#ifndef _CACHE_HPP_
#define _CACHE_HPP_
#include "cache.h"
#include "md5.h"
using namespace std;
using namespace ycache;
template<typename K, typename V> 
Cache<K,V>::Cache(int maxSize){
	m_maxSize=maxSize;

};
template<typename K, typename V> 
void Cache<K,V>::SetMaxSize(int maxSize){
	m_maxSize=maxSize;

};
template< typename V> 
MD5Cache<V>::MD5Cache(int maxSize):Cache<MD5_DATA,V>(maxSize){
}


template <typename K, typename V> 
void Cache<K,V>::Hit(const  K & k){
	Guard grLRU(m_mutexLRU);
	typename map< K,typename list<K>::iterator>::iterator  mitr = m_mapLRU.find(k);
	typename list<K>::iterator litrLRU ;
	if(mitr!=m_mapLRU.end()){
		litrLRU=mitr->second;
		m_listLRU.erase(litrLRU);
	}
	m_listLRU.push_back(k);
    litrLRU=m_listLRU.end(); 
	litrLRU--;
	m_mapLRU[k]=litrLRU;
	
}
template < typename V> 
int MD5Cache<V>::Put(const MD5_DATA  & k  ,const V & v){
   return  Cache<MD5_DATA,V>::Put(k,v);
};
template < typename V> 
int MD5Cache<V>::Put(const string & k  ,const V & v){
   CMD5 cmd5;
   cmd5.GenerateMD5((unsigned char *)k.c_str(),k.length());
   MD5_DATA data;
   data=cmd5.m_data;
   return  Cache<MD5_DATA,V>::Put(data,v);
}
template < typename V> 
bool MD5Cache<V>::Get(const string & k  ,V & v){
   CMD5 cmd5;
   cmd5.GenerateMD5((unsigned char * )k.c_str(),k.length());
   MD5_DATA data;
   data=cmd5.m_data;
   //return Cache<MD5_DATA,V>::Get(cmd5,v);
   //return this->template Get<MD5_DATA,V>(cmd5,v);
   return Cache<MD5_DATA,V>::Get(data,v);
}
template <typename K, typename V> 
bool Cache<K,V>::Get(const  K & k  ,V & v){
	{
		RWGuard gr(m_rwmutexData);
		typename map<K,V>::iterator itr= m_mapData.find(k);
		if (itr == m_mapData.end() ){
			return false;
		}
		v=itr->second;
	}
	Hit(k);
	return true;
	
};
template<typename K, typename V>
int  Cache<K,V>::Put(const K & k , const V & v){
    int ret=0;
	{
		RWGuard gr(m_rwmutexData,true);
		typename map<K,V>::iterator itr= m_mapData.find(k);
		if (itr == m_mapData.end() ){
			m_mapData.insert(itr,typename map<K,V>::value_type(k,v) );
			ret = 1;
		}else{
			itr->second=v;
		}
		
	}
	Hit(k);
	return ret;
}
template <typename K , typename V>
int Cache<K,V>::Clear(){
	int dlen=0;
	list < K > listToDel;
	{
		Guard grLRU(m_mutexLRU);
		dlen=m_listLRU.size()-m_maxSize;
		if(dlen< m_maxSize*0.1){
			return 0;
		}

		typename list < K >::iterator itrS = m_listLRU.begin ();
		typename list < K >::iterator itrE = itrS;
		advance (itrE, dlen);
		for (typename list < K >::iterator itrDel = itrS; itrDel != itrE; itrDel++)
		{   
			listToDel.push_back (*itrDel);
			m_mapLRU.erase(*itrDel);
		}
		m_listLRU.erase(itrS,itrE);
	}	
	{
		RWGuard gr(m_rwmutexData,true);
		for(typename list<K>::iterator itrDel = listToDel.begin(); itrDel!=listToDel.end();itrDel++){
			m_mapData.erase(*itrDel);
		}
	}

	return dlen;
	
}

#endif
